package com.rabbit.service;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.GetObjectRequest;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.SimplifiedObjectMeta;
import com.rabbit.constant.FileType;
import com.rabbit.constant.ResultCodeEnum;
import com.rabbit.dto.OssFileDTO;
import com.rabbit.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.math.RoundingMode;


/**
 * Created by zjw on 2022/3/13 2:45 下午
 */
@Service
@Slf4j
@ConditionalOnProperty(name = "aliyun.oss.enable", havingValue = "true")
public class OssService {

    @Value("${aliyun.oss.accessKeyId}")
    private String accessKeyId;

    @Value("${aliyun.oss.accessKeySecret}")
    private String accessKeySecret;

    @Value("${aliyun.oss.endpoint}")
    private String endpoint;

    @Value("${aliyun.oss.bucketName}")
    private String bucketName;

    /**
     * 拼接头像文件Url
     *
     * @param fileUrl 文件Url
     * @return 完整Url
     */
    public String packageAvatarUrl(String fileUrl) {
        if (endpoint.contains("https")) {
            return endpoint.substring(0, 8) + bucketName + "." + endpoint.substring(8) + File.separator + fileUrl;
        } else {
            return endpoint.substring(0, 7) + bucketName + "." + endpoint.substring(7) + File.separator + fileUrl;
        }
    }

    /**
     * 上传头像
     *
     * @param userId  用户编号
     * @param fileUrl 文件路径
     * @return OssFileDTO
     * @throws BusinessException
     */
    public OssFileDTO uploadAvatar(Long userId, String fileUrl) throws BusinessException {
        String fileName = fileUrl.substring(fileUrl.lastIndexOf(File.separator) + 1);
        String objectName = "avatar/" + userId + "/" + fileName;

        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        try {
            ossClient.putObject(bucketName, objectName, new FileInputStream(fileUrl));
            SimplifiedObjectMeta objectMeta = ossClient.getSimplifiedObjectMeta(bucketName, objectName);
            BigDecimal fileSize = BigDecimal.valueOf(objectMeta.getSize()).divide(BigDecimal.valueOf(1048576), 2, RoundingMode.HALF_UP);
            return OssFileDTO.builder().fileName(fileName)
                    .fileSize(fileSize).fileType(FileType.AVATAR).fileUrl(objectName)
                    .uploadTime(objectMeta.getLastModified()).build();
        } catch (OSSException oe) {
            log.error("OSS处理异常,具体信息:", oe);
            throw new BusinessException(ResultCodeEnum.USER_AVATAR_UPDATE_ERROR);
        } catch (ClientException ce) {
            log.error("OSS客户端建立连接异常,具体信息:", ce);
            throw new BusinessException(ResultCodeEnum.USER_AVATAR_UPDATE_ERROR);
        } catch (FileNotFoundException e) {
            // 忽略FileNotFoundException,有前置判断
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
        return null;
    }

    /**
     * 删除文件或目录(如果要删除目录，目录必须为空)
     *
     * @param objectName 文件或目录Url
     */
    public void deleteObject(String objectName) {
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        ossClient.deleteObject(bucketName, objectName);
        ossClient.shutdown();
    }

    /**
     * 下载文件
     *
     * @param objectName 文件url
     * @param response   响应对象
     */
    public void downloadFile(String objectName, HttpServletResponse response) {
        String fileName = objectName.substring(objectName.lastIndexOf("/") + 1);
        response.reset();
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/octet-stream");
        response.addHeader("Content-Disposition",
                "attachment;filename=" + fileName);
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        OSSObject ossObject = ossClient.getObject(new GetObjectRequest(bucketName, objectName));
        byte[] buffBytes = new byte[1024];
        int read;
        try (OutputStream outputStream = response.getOutputStream();
             BufferedInputStream input = new BufferedInputStream(ossObject.getObjectContent())) {
            while ((read = input.read(buffBytes)) != -1) {
                outputStream.write(buffBytes, 0, read);
            }
            outputStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        ossClient.shutdown();
    }
}
